namespace ts.server {
    export interface InstallPackageOptionsWithProject extends InstallPackageOptions {
        projectName: string;
        projectRootPath: Path;
    }

    // for backwards-compatibility
    // eslint-disable-next-line @typescript-eslint/interface-name-prefix
    export interface ITypingsInstaller {
        isKnownTypesPackageName(name: string): boolean;
        installPackage(options: InstallPackageOptionsWithProject): Promise<ApplyCodeActionCommandResult>;
        attach(projectService: ProjectService): void;
        onProjectClosed(p: Project): void;
        readonly globalTypingsCacheLocation: string | undefined;
    }

    export const nullTypingsInstaller: ITypingsInstaller = {
        isKnownTypesPackageName: returnFalse,
        // Should never be called because we never provide a types registry.
        installPackage: notImplemented,
        attach: noop,
        onProjectClosed: noop,
        globalTypingsCacheLocation: undefined! // TODO: GH#18217
    };

    interface TypingsCacheEntry {
        readonly compilerOptions: CompilerOptions;
        readonly typings: SortedReadonlyArray<string>;
        readonly unresolvedImports: SortedReadonlyArray<string> | undefined;
        /* mainly useful for debugging */
        poisoned: boolean;
    }

    /*@internal*/
    export class TypingsCache {
        private readonly perProjectCache: Map<TypingsCacheEntry> = createMap<TypingsCacheEntry>();

        constructor(private readonly installer: ITypingsInstaller) {
        }

        isKnownTypesPackageName(name: string): boolean {
            return this.installer.isKnownTypesPackageName(name);
        }

        installPackage(options: InstallPackageOptionsWithProject): Promise<ApplyCodeActionCommandResult> {
            return this.installer.installPackage(options);
        }

        updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, unresolvedImports: SortedReadonlyArray<string>, newTypings: string[]) {
            const typings = sort(newTypings);
            this.perProjectCache.set(projectName, {
                compilerOptions,
                typings,
                unresolvedImports,
                poisoned: false
            });
            return emptyArray;
        }

        onProjectClosed(project: Project) {
            this.perProjectCache.delete(project.getProjectName());
            this.installer.onProjectClosed(project);
        }
    }
}
